//============================================================================
// Name        : eBrainAutoTraining.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include "stdafx.h"
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>

#include "CeBrain.h"
int AutoTrainingByValue();
int AutoTrainingByLink();
int AutoTrainingByValueAndLink();

int main(int argc,char *argv[])
{
	if( argc>1 )
	{
		if( *argv[1] == '0')
			return AutoTrainingByValue();
		else if( *argv[1] == '1' )
			return AutoTrainingByLink();
		else if( *argv[1] == '2' )
			return AutoTrainingByValueAndLink();
	}
	TRACE("0 or 1 or 2\n");
}

bool FindSourceLink( NervusLink* pLinks, int nLinksCount, int nColumn, int nRow, int pin )
{
	int nFoundIdx=0;
	for( nFoundIdx=0; nFoundIdx<nLinksCount; nFoundIdx++ )
		if( nColumn == pLinks[nFoundIdx].posSource.nColumn && nRow == pLinks[nFoundIdx].posSource.nRow && pin == pLinks[nFoundIdx].pin )
			break;
	return nFoundIdx < nLinksCount;
}

int PrepareNervusLinks( NervusLink* pNervusLinks, NervusLink* pCutLinks, int nCutLinksCount )
{
	int nLinksCount = 0;
	for( int i=0; i<NERVUS_MAP_WIDTH; i++ )
		for( int j=0; j<NERVUS_MAP_DEPTH; j++ )
		{
			NervusPOS pos = {i,j};
			NervusPOS posTarget;
			for( int k=0; k<NERVUS_ANTENNA_NUM; k++ )
			{
				if( k==0 )
				{
					posTarget.nColumn = i;
					posTarget.nRow = j+1>=NERVUS_MAP_DEPTH ? 0 : j+1;
					if( j==NERVUS_MAP_DEPTH-1 )
						continue; //ignore for output pin.
				}
				else if( k== 1 )
				{
					posTarget.nColumn = i+1>=NERVUS_MAP_WIDTH ? 0 : i+1;
					posTarget.nRow = j+1>=NERVUS_MAP_DEPTH ? 0 : j+1;
				}
				else if( k== 2 )
				{
					posTarget.nColumn = i+1>=NERVUS_MAP_WIDTH ? 0 : i+1;
					posTarget.nRow = j;
				}

				if( FindSourceLink( pCutLinks, nCutLinksCount, pos.nColumn, pos.nRow, k) )
				{
					TRACE( "cut connect from {%d,%d}, %d, to {%d,%d}\n", pos.nColumn, pos.nRow, k, posTarget.nColumn, posTarget.nRow );
					continue;
				}
				pNervusLinks[ nLinksCount ].posSource = pos;
				pNervusLinks[ nLinksCount ].pin = k;
				pNervusLinks[ nLinksCount ].posTarget = posTarget;
				nLinksCount++;
			}
		}
	return nLinksCount;
}

int AutoTrainingByLink(){
	CeBrain m_eBrain;

	float fPassRate = 0, fMaxPassRate = 0;

	NervusValue *nv;

	struct  stat nv_stat;
	int fnv = open( "NV_lastbest.bin", O_RDONLY );
	if( !fnv )
	{
		TRACE("NV_lastbest.bin not found!\n");
		return 0;
	}
	fstat (fnv, &nv_stat);
	int nNervusValuesCount = nv_stat.st_size/sizeof(NervusValue);
	nv = new NervusValue[ nv_stat.st_size/sizeof(NervusValue)];
	close( fnv );

	FILE* fNv = fopen( "NV_lastbest.bin", "rb+" );
	fread( nv, sizeof(NervusValue), nNervusValuesCount, fNv );
	fclose( fNv );

	NervusLink NL[ NERVUS_MAP_WIDTH*NERVUS_MAP_DEPTH*NERVUS_ANTENNA_NUM ];
	int nNervusLinksCount = 0;
	NervusLink NlGood[ NERVUS_MAP_WIDTH*NERVUS_MAP_DEPTH*NERVUS_ANTENNA_NUM ];
	int nNlGoodCount = 0;

	NervusLink nl_cut[60];
	int nCurrentCutLinksIdx = 0;

	NervusLink nl_good={{0,0},0,{0,0}};

	char f_name[100];

	while(1)
	{
		fMaxPassRate = 0;

		for( int i=0; i<NERVUS_MAP_WIDTH; i++ )
			for( int j=0; j<NERVUS_MAP_DEPTH; j++ )
				for( int cut_pin=1; cut_pin<NERVUS_ANTENNA_NUM; cut_pin++)
				{
					NervusPOS cut_pos = {i,j};
					nl_cut[nCurrentCutLinksIdx].posSource = cut_pos;
					nl_cut[nCurrentCutLinksIdx].pin = cut_pin;
					nNervusLinksCount = PrepareNervusLinks( NL, nl_cut, nCurrentCutLinksIdx+1 );
					m_eBrain.SetNervusLinks( NL, nNervusLinksCount );
					m_eBrain.SetNervusValues( nv, nNervusValuesCount );
					fPassRate = m_eBrain.RunAllTrainingCase( NV_EMPTY_VALUE );
					//fPassRate=(i+1)/(j+1)*0.1;
					if( fMaxPassRate < fPassRate )
					{
						if( nCurrentCutLinksIdx>0 )
						{
							if( !FindSourceLink( nl_cut, nCurrentCutLinksIdx, cut_pos.nColumn, cut_pos.nRow, cut_pin) )
							{
								fMaxPassRate = fPassRate;
								nl_good.posSource = cut_pos;
								nl_good.pin = cut_pin;
								nNlGoodCount = nNervusLinksCount;
								memcpy( NlGood, NL, sizeof(NervusLink)*nNlGoodCount );
							}
						}
						else
						{
							fMaxPassRate = fPassRate;
							nl_good.posSource = cut_pos;
							nl_good.pin = cut_pin;
							nNlGoodCount = nNervusLinksCount;
							memcpy( NlGood, NL, sizeof(NervusLink)*nNlGoodCount );
						}
					}
				}

		nl_cut[nCurrentCutLinksIdx].posSource = nl_good.posSource;
		nl_cut[nCurrentCutLinksIdx].pin = nl_good.pin;
		nCurrentCutLinksIdx++;

		TRACE( "Max Pass Rate is %f%%, link is [%d-%d:%d:%d-%d]\n", fMaxPassRate,
				nl_good.posSource.nColumn, nl_good.posSource.nRow, nl_good.pin,
				nl_good.posTarget.nColumn, nl_good.posTarget.nRow );

		{
			sprintf( f_name, "NL_%d_%lf-%d_%d_%d.bin", nCurrentCutLinksIdx, fMaxPassRate, nl_good.posSource.nColumn, nl_good.posSource.nRow, nl_good.pin );
			FILE* f_nv = fopen( f_name, "wb+" );
			fwrite( NlGood, sizeof(NervusLink), nNlGoodCount, f_nv );
			fclose( f_nv );
		}
		if( nCurrentCutLinksIdx>= 40 )
			break;
	}
	TRACE( "Final Max Pass Rate is %lf!\n", fMaxPassRate );
	delete nv;
	return 0;

}

int AutoTrainingByValue(){
	CeBrain m_eBrain;

	//double d, max_d, last_d=0;
	int try_value, good_value, last_value=0;
	float fPassRate = 0, fMaxPassRate = 0, fLastMaxPassRate;
	/*NervusValue v[]={
		{{0,2},0,10}, {{1,2},10,10}, {{2,2},10,10}, {{3,2},10,10},
		{{0,3},10,10}, {{1,3},10,10}, {{2,3},10,10}, {{3,3},10,10},
		{{0,4},10,10}, {{1,4},10,10}, {{2,4},10,10}, {{3,4},10,10},
		{{0,1},10,10}, {{1,1},10,10}, {{2,1},10,10}, {{3,1},10,10},
		{{0,5},10,10}, {{1,5},10,10}, {{2,5},10,10}, {{3,5},10,10},
		{{0,0},10,10}, {{1,0},10,10}, {{2,0},10,10}, {{3,0},10,10},
	};*/

	//int nNervusValuesCount = sizeof(v)/sizeof(NervusValue);
	NervusValue nv[NERVUS_MAP_WIDTH*NERVUS_MAP_DEPTH];
	int nNervusValuesCount = NERVUS_MAP_WIDTH*NERVUS_MAP_DEPTH;
	int nidx = 0;
	//for( int o=NERVUS_MAP_WIDTH-1; o>=0; o--)
		//for( int p=NERVUS_MAP_DEPTH-1; p>=0; p--)
	for( int p=0; p<NERVUS_MAP_DEPTH; p++)
		for( int o=0; o<NERVUS_MAP_WIDTH; o++)
		{
			nv[nidx].pos.nColumn = o;
			nv[nidx].pos.nRow = p;
			nv[nidx].value_real = 0;
			nv[nidx].value_image = 70;
			nidx++;
		}

	int try_value_idx = 0;
	bool try_real = true;
	nv[try_value_idx].value_real = NV_EMPTY_VALUE;

	char f_name[100];

	while(1)
	{
		fMaxPassRate = 0;

		for( try_value= (last_value==NV_EMPTY_VALUE)? 31: last_value+30; try_value>=0; try_value-=1 )
		{
			m_eBrain.SetNervusValues( nv, nNervusValuesCount );
			fPassRate = m_eBrain.RunAllTrainingCase( try_value/NV_DEVIDER );
			if( fMaxPassRate < fPassRate )
			{
				fMaxPassRate = fPassRate;
				good_value = try_value;
			}
		}
		TRACE( "Max Pass Rate of [%d-%d~%d] is %f%%, value is %lf, old is %lf\n", fMaxPassRate,nv[ try_value_idx ].pos.nColumn, nv[ try_value_idx ].pos.nRow, try_real?0:1, good_value/NV_DEVIDER, last_value/NV_DEVIDER );

		if( try_real )
		{
			nv[ try_value_idx ].value_real = good_value;
		}
		else
		{
			nv[ try_value_idx ].value_image = good_value;
		}

		{
			sprintf( f_name, "NV_%lf-%d_%d_%d.bin", fMaxPassRate, nv[ try_value_idx ].pos.nColumn, nv[ try_value_idx ].pos.nRow, try_real?0:1 );
			FILE* f_nv = fopen( f_name, "wb+" );
			fwrite( nv, sizeof(NervusValue), nNervusValuesCount, f_nv );
			fclose( f_nv );
		}

		if( try_value_idx==0 && try_real )
		{
			if( fLastMaxPassRate == 0 )
				fLastMaxPassRate = fMaxPassRate;
			else
			{
				TRACE("last max is %lf\n", fLastMaxPassRate);
				if( fLastMaxPassRate >= fMaxPassRate )
					break;
				else
					fLastMaxPassRate = fMaxPassRate;
			}
		}

		try_real = !try_real;
		if( try_real )
		{
			++try_value_idx;
			if( try_value_idx >= nNervusValuesCount )
				try_value_idx = 0;
			last_value = nv[ try_value_idx ].value_real;
			nv[ try_value_idx ].value_real = NV_EMPTY_VALUE;
		}
		else
		{
			last_value = nv[ try_value_idx ].value_image;
			nv[ try_value_idx ].value_image = NV_EMPTY_VALUE;
		}
	}
	TRACE( "Final Max Pass Rate is %lf!\n", fMaxPassRate );
	return 0;

}

int AutoTrainingByValueAndLink(){
	CeBrain m_eBrain;

	//double d, max_d, last_d=0;
	int try_value, good_value, last_value=0;
	float fPassRate = 0, fMaxPassRate = 0, fLastMaxPassRate;

	int nidx = 0;

	NervusValue *nv;

	struct  stat nv_stat;
	int fnv = open( "NV_lastbest.bin", O_RDONLY );
	if( !fnv )
	{
		TRACE("NV_lastbest.bin not found!\n");
		return 0;
	}
	fstat (fnv, &nv_stat);
	int nNervusValuesCount = nv_stat.st_size/sizeof(NervusValue);
	nv = new NervusValue[ nv_stat.st_size/sizeof(NervusValue)];
	close( fnv );

	FILE* fNv = fopen( "NV_lastbest.bin", "rb+" );
	fread( nv, sizeof(NervusValue), nNervusValuesCount, fNv );
	fclose( fNv );

	NervusLink *nl;

	struct  stat nl_stat;
	int fnl = open( "NL_last.bin", O_RDONLY );
	if( !fnl )
	{
		TRACE("NL_last.bin not found!\n");
		return 0;
	}
	fstat (fnl, &nl_stat);
	int nNervusLinksCount = nl_stat.st_size/sizeof(NervusLink);
	nl = new NervusLink[ nl_stat.st_size/sizeof(NervusLink)];
	close( fnl );

	FILE* fNl = fopen( "NL_last.bin", "rb+" );
	fread( nl, sizeof(NervusLink), nNervusLinksCount, fNl );
	fclose( fNl );

	int try_value_idx = 0;
	bool try_real = true;
	nv[try_value_idx].value_real = NV_EMPTY_VALUE;

	char f_name[100];

	while(1)
	{
		fMaxPassRate = 0;

		for( try_value= (last_value==NV_EMPTY_VALUE)? 31: last_value+30; try_value>=0; try_value-=1 )
		{
			m_eBrain.SetNervusLinks( nl, nNervusLinksCount );
			m_eBrain.SetNervusValues( nv, nNervusValuesCount );
			fPassRate = m_eBrain.RunAllTrainingCase( try_value/NV_DEVIDER );
			if( fMaxPassRate < fPassRate )
			{
				fMaxPassRate = fPassRate;
				good_value = try_value;
			}
		}
		TRACE( "Max Pass Rate of [%d-%d~%d] is %f%%, value is %lf, old is %lf\n", fMaxPassRate,nv[ try_value_idx ].pos.nColumn, nv[ try_value_idx ].pos.nRow, try_real?0:1, good_value/NV_DEVIDER, last_value/NV_DEVIDER );

		if( try_real )
		{
			nv[ try_value_idx ].value_real = good_value;
		}
		else
		{
			nv[ try_value_idx ].value_image = good_value;
		}

		{
			sprintf( f_name, "NV_%lf-%d_%d_%d.bin", fMaxPassRate, nv[ try_value_idx ].pos.nColumn, nv[ try_value_idx ].pos.nRow, try_real?0:1 );
			FILE* f_nv = fopen( f_name, "wb+" );
			fwrite( nv, sizeof(NervusValue), nNervusValuesCount, f_nv );
			fclose( f_nv );
		}

		if( try_value_idx==0 && try_real )
		{
			if( fLastMaxPassRate == 0 )
				fLastMaxPassRate = fMaxPassRate;
			else
			{
				TRACE("last max is %lf\n", fLastMaxPassRate);
				if( fLastMaxPassRate >= fMaxPassRate )
					break;
				else
					fLastMaxPassRate = fMaxPassRate;
			}
		}

		try_real = !try_real;
		if( try_real )
		{
			++try_value_idx;
			if( try_value_idx >= nNervusValuesCount )
				try_value_idx = 0;
			last_value = nv[ try_value_idx ].value_real;
			nv[ try_value_idx ].value_real = NV_EMPTY_VALUE;
		}
		else
		{
			last_value = nv[ try_value_idx ].value_image;
			nv[ try_value_idx ].value_image = NV_EMPTY_VALUE;
		}
	}
	TRACE( "Final Max Pass Rate is %lf!\n", fMaxPassRate );
	return 0;

}
